﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using PlanningGIS.ArcGIS;
using PlanningGIS.Framework;
using PlanningGIS.Framework.Rule;
using PlanningGIS.Util.Log;
using PlanningGIS.Win.Controls;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.DataManagementTools;

namespace PlanningGIS.DataConvert
{
    /// <summary>
    /// 数据操作
    /// </summary>
    public class ImpJob
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public ImpJob()
        {

        }
        
        /// <summary>
        /// 获取或设置分进度条
        /// </summary>
        public Progressor ProgressSub { get; set; }

        /// <summary>
        /// 获取或设置总进度条
        /// </summary>
        public Progressor ProgressAll { get; set; }

        /// <summary>
        /// 要提交的记录总数
        /// </summary>
        private int _FlushCount = 100;

        /// <summary>
        /// 目标工作空间
        /// </summary>
        protected IWorkspace _WorkspaceTarget = null;

        /// <summary>
        /// 获取目标工作空间
        /// </summary>
        public IWorkspace WorkspaceTarget
        {
            get
            {
                if (_WorkspaceTarget == null)
                {
                    if (ImportRule != null)
                    {
                        if ("sde".Equals(ImportRule.WorkspaceType, StringComparison.CurrentCultureIgnoreCase))
                        {
                            _FlushCount = 100;
                            _WorkspaceTarget = PlanningGIS.ArcGIS.WorkspaceHelper.OpenSDEWorkspace(ImportRule.Server, ImportRule.User, ImportRule.Password, ImportRule.Database);
                          //  _WorkspaceTarget.PathName
                        }
                        else
                        {
                            _FlushCount = 1000;
                            _WorkspaceTarget = PlanningGIS.ArcGIS.WorkspaceHelper.CreateOrOpenWorksapce(ImportRule.Path);
                        }                            
                    }
                }
                return _WorkspaceTarget;
            }
            set { _WorkspaceTarget = value; }
        }

        /// <summary>
        /// 获取目标数据集对象
        /// </summary>
        public IFeatureDataset DatasetTarget { get; protected set; }

        /// <summary>
        /// 要入库的源数据集合,暂时只支持IFeatureClass，后期可以考虑IName（可以提高性能）
        /// </summary>
        public List<IFeatureClass> FeatureClassSource { get; set; }

        /// <summary>
        /// 需要入到的目标数据集合
        /// </summary>
        public List<IFeatureClass> FeatureClassTarget { get; set; }

        /// <summary>
        /// 创建库体用的入库基本规则
        /// </summary>
        public DataImportRule ImportRule { get; set; }

        /// <summary>
        /// 源数据与目标数据代码对应关系
        /// </summary>
        public List<FcodeRelation> FeatureCodes { get; set; }

        /// <summary>
        /// 获取或设置图层入库时图层与字段的匹配关系
        /// </summary>
        public List<MatchFieldName> MatchNames { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public List<MatchFieldIndex> MatchIndexes { get; set; }

        public string SdeFile { get; set; }
        public string Affix { get; set; }
       
        public string FeatureDatasetName { get; set; }

        /// <summary>
        /// 规则中不存在的分类代码，避免重复提示
        /// </summary>
        private List<string> _NewFCodes = null;

        /// <summary>
        /// 是否终止操作
        /// </summary>
        public bool IsStop { get; set; }

        /// <summary>
        /// 是否利用Append GP工具
        /// </summary>
        public bool useAppendGP = false;

        /// <summary>
        /// XY空间参考，Z的空间参考(SpatialRef as ISpatialReference3).VerticalCoordinateSystem = IVerticalCoordinateSystem。
        /// 使用ISpatialReferenceFactory3.CreateVerticalCoordinateSystemFromESRISpatialReference进行创建
        /// </summary>
        public ISpatialReference SpatialRef { get; set; }

      

        /// <summary>
        /// 构造对应关系（代码之间的关系、字段之间的关系、字段默认值以及剔除掉不符合要求的数据源）
        /// </summary>
        /// <returns></returns>
        public bool Import()
        {
            if (!CreateFeatureDataset()) return false;
            if (!CreateFeatureClass()) return false;
            LogHelper.WriteLog("\n");
            IsStop = false;
            DateTime start = DateTime.Now;
            ProgressAll.SetMaxValue(FeatureClassSource.Count);
            bool hasFalse = false;
            foreach (dynamic cls in FeatureClassSource)
            {
                ProgressAll.Step();
                if (IsStop) break;
                if (cls is IFeatureClass)
                {
                    try
                    {
                        if (MatchNames == null)
                        {
                            if (!IntoFCode(cls as IFeatureClass)) hasFalse = true;
                        }
                        else
                        {
                            if (!IntoLayer(cls as IFeatureClass)) hasFalse = true;
                        }
                    }
                    catch (Exception ex)
                    {
                        hasFalse = true;
                        LogHelper.WriteLog(ex);
                    }
                }
            }
            ProgressAll.Stop();
            TimeSpan time = DateTime.Now - start;
            LogHelper.WriteLog(string.Format("入库完成，共耗时：{0}小时{1}分钟{2}秒\n", time.Hours, time.Minutes, time.Seconds));
            return !hasFalse;
        }

        public bool CopyFcls()
        {
          
            FeatureClassTarget = new List<IFeatureClass>();
            //foreach (MatchFieldName ms in MatchNames)
            //{
            //    if ((WorkspaceTarget as IWorkspace2).get_NameExists(esriDatasetType.esriDTFeatureClass, ms.TargetName))
            //    {
            //        IFeatureClass featcls = (WorkspaceTarget as IFeatureWorkspace).OpenFeatureClass(ms.TargetName);
            //        FeatureClassTarget.Add(featcls);
            //    }
            //}
            LogHelper.WriteLog("\n");
            IsStop = false;
            DateTime start = DateTime.Now;
            ProgressAll.SetMaxValue(FeatureClassSource.Count);
            bool hasFalse = false;
            foreach (dynamic cls in FeatureClassSource)
            {
                ProgressAll.Step();
                if (IsStop) break;
                if (cls is IFeatureClass)
                {
                    try
                    {
                        if (!ImportByCopyGpTool(cls as IFeatureClass)) hasFalse = true;
                    }
                    catch (Exception ex)
                    {
                        hasFalse = true;
                        LogHelper.WriteLog(ex);
                    }
                }
            }
            ProgressAll.Stop();
            TimeSpan time = DateTime.Now - start;
            LogHelper.WriteLog(string.Format("入库完成，共耗时：{0}小时{1}分钟{2}秒\n", time.Hours, time.Minutes, time.Seconds));
            return !hasFalse;
        }

        /// <summary>
        /// 按图层匹配本地数据入库
        /// </summary>
        /// <returns></returns>
        public bool ImportData()
        {
            if (MatchNames == null || MatchNames.Count == 0)
            {
                MsgHelper.ShowErrorMsgbox( "未进行图层字段匹配。");
                return false;
            }
            FeatureClassTarget = new List<IFeatureClass>();
            foreach (MatchFieldName ms in MatchNames)
            {
                if ((WorkspaceTarget as IWorkspace2).get_NameExists(esriDatasetType.esriDTFeatureClass, ms.TargetName))
                {
                    IFeatureClass featcls = (WorkspaceTarget as IFeatureWorkspace).OpenFeatureClass(ms.TargetName);
                    FeatureClassTarget.Add(featcls);
                }
            }
            LogHelper.WriteLog("\n");
            IsStop = false;
            DateTime start = DateTime.Now;
            ProgressAll.SetMaxValue(FeatureClassSource.Count);
            bool hasFalse = false;
            foreach (dynamic cls in FeatureClassSource)
            {
                ProgressAll.Step();
                if (IsStop) break;
                if (cls is IFeatureClass)
                {
                    try
                    {
                        if (!IntoLayer(cls as IFeatureClass)) hasFalse = true;
                    }
                    catch (Exception ex)
                    {
                        hasFalse = true;
                        LogHelper.WriteLog(ex);
                    }
                }
            }
            ProgressAll.Stop();
            TimeSpan time = DateTime.Now - start;
            LogHelper.WriteLog(string.Format("入库完成，共耗时：{0}小时{1}分钟{2}秒\n", time.Hours, time.Minutes, time.Seconds));
            return !hasFalse;
        }

        /// <summary>
        /// 终止入库操作
        /// </summary>
        public void Stop()
        {
            IsStop = true;
        }

        #region 创建要素类与数据集
        /// <summary>
        /// 构建目标数据集对象
        /// </summary>
        /// <returns></returns>
        public bool CreateFeatureDataset()
        {
            if (string.IsNullOrWhiteSpace(ImportRule.DatasetName)) return true;
            string dsname = ImportRule.DatasetName.Trim();
            if (!string.IsNullOrWhiteSpace(ImportRule.Affix) && !dsname.ToLower().EndsWith(ImportRule.Affix.Trim().ToLower()))
                dsname += ImportRule.Affix.Trim();
            LogHelper.WriteLog("开始构建目标数据集[" + dsname + "]对象...");
            if (((IWorkspace2)WorkspaceTarget).get_NameExists(esriDatasetType.esriDTFeatureDataset, dsname))
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("数据集已存在，是否确定将数据追加到已有的数据集中？");
                sb.Append("\n是：将数据追加到已有的要素类中，若要素类不存在，则重新构建。");
                sb.Append("\n否：退出入库，重新选择一个空的数据库");
                if (MsgHelper.ShowYesOrNoQueryMsgBox(sb.ToString()) != System.Windows.Forms.DialogResult.Yes)
                {
                    LogHelper.WriteLog("已取消创建数据集，并终止入库。");
                    return false;
                }
                DatasetTarget = (WorkspaceTarget as IFeatureWorkspace).OpenFeatureDataset(dsname);
            }
            else
            {
                DatasetTarget = (WorkspaceTarget as IFeatureWorkspace).CreateFeatureDataset(dsname, SpatialRef);
            }
            LogHelper.WriteLog("目标数据集构建完成。\n");
            return true;
        }

        /// <summary>
        /// 创建目标图层
        /// </summary>
        /// <returns></returns>
        public bool CreateFeatureClass()
        {
            LogHelper.WriteLog("开始构建目标要素类...");
            ProgressAll.SetMaxValue(ImportRule.dlgTargetFeatureClasses.Count);            
            FeatureCodes = new List<FcodeRelation>();
            FeatureClassTarget = new List<IFeatureClass>();
            bool hasFalse = false;
            bool hasTipClass = false;
            foreach (DlgTargetFeatureClass itm in ImportRule.dlgTargetFeatureClasses)
            {
                if (IsStop) return false;
                ProgressAll.Step();
                string clsname = itm.FeatureClassName.Trim();
                if (!string.IsNullOrWhiteSpace(ImportRule.Affix) && !clsname.ToLower().EndsWith(ImportRule.Affix.Trim().ToLower()))
                    clsname += ImportRule.Affix;
                if (itm.GeometryType == "注记")
                {
                    bool hasAnno = FeatureClassSource.Any(t =>
                    {
                        if (t is IFeatureClass)
                            return (t as IFeatureClass).FeatureType == esriFeatureType.esriFTAnnotation;
                        return false;
                    });
                    if (!hasAnno)
                    {
                        LogHelper.WriteLog("不存在要入库的注记，无法读取注记的比例尺，暂时不用创建注记层[" + clsname + "]");
                        continue;
                    } 
                }                
                List<FcodeRelation> codes = CreateFcodeRelation(clsname, itm);
                if (codes != null && codes.Count > 0) FeatureCodes.AddRange(codes);                
                LogHelper.WriteLog("开始构建目标要素类[" + clsname + "]...");
                if ((WorkspaceTarget as IWorkspace2).get_NameExists(esriDatasetType.esriDTFeatureClass, clsname))
                {
                    if (!hasTipClass)
                    {
                        StringBuilder sb = new StringBuilder();
                        sb.Append("目标要素类已存在，是否确定将数据追加到已有的要素类中？");
                        sb.Append("\n是：将数据追加到已有的要素类中。");
                        sb.Append("\n否：退出入库，重新选择一个空的数据库");
                        if (MsgHelper.ShowYesOrNoQueryMsgBox(sb.ToString()) != System.Windows.Forms.DialogResult.Yes)
                        {
                            LogHelper.WriteLog("已取消创建目标要素类，并终止入库。");
                            return false;
                        }
                        hasTipClass = true;
                    }
                    IFeatureClass featcls = (WorkspaceTarget as IFeatureWorkspace).OpenFeatureClass(clsname);
                    FeatureClassTarget.Add(featcls);
                    LogHelper.WriteLog("目标要素类已存在，直接打开...");
                }
                else
                {
                    if (!CreateFeatureClass(clsname, itm as DlgTargetFeatureClassBase)) hasFalse = true;
                }
            }
            return !hasFalse;
        }

        /// <summary>
        /// 构建目标要素类
        /// </summary>
        /// <param name="clsname">要素类的名称</param>
        /// <param name="rule">构建规则</param>
        /// <returns></returns>
        private bool CreateFeatureClass(string clsname, DlgTargetFeatureClassBase rule)
        {
            IFieldChecker fdChecker = new FieldChecker();
            fdChecker.ValidateWorkspace = WorkspaceTarget;
            string fixedName = "";
            fdChecker.ValidateTableName(clsname, out fixedName);
            if (!clsname.Equals(fixedName, StringComparison.CurrentCultureIgnoreCase))
            {
                LogHelper.WriteErrLog("目标要素类[" + clsname + "]的名称不符合规范，请重新设置！");
                return false;
            }
            IFields fds = CreateFields(rule.attrFields);
            if (fds == null) return false;
            IFeatureClass featcls = null;
            try
            {
                if (rule.GeometryType.Equals("注记"))
                {
                    dynamic cls = FeatureClassSource.FirstOrDefault(t =>
                    {
                        if (t is IFeatureClass)
                            return (t as IFeatureClass).FeatureType == esriFeatureType.esriFTAnnotation;
                        return false;
                    });
                    if (cls is IFeatureClass)//有注记需要入库
                    {
                        featcls = GeodatabaseHelper.CreateAnnotationFeatureClass(WorkspaceTarget, clsname, fds, cls as IFeatureClass, DatasetTarget, SpatialRef);
                    }
                }
                else
                    featcls = CreateSimple(clsname, rule.GeometryType, fds, rule.HasM, rule.HasZ);
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrLog("目标要素类[" + clsname + "]创建失败：" + ex.Message);
                return false;
            }
            if (featcls == null) return false;
            LogHelper.WriteLog("目标要素类[" + clsname + "]创建成功！");
            try
            {
                if (!string.IsNullOrWhiteSpace(rule.FeatureClassAliasName))
                {
                    IClassSchemaEdit clsSchemaEdit = featcls as IClassSchemaEdit;
                    clsSchemaEdit.AlterAliasName(rule.FeatureClassAliasName.Trim());
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrLog("给目标要素类[" + clsname + "]赋别名时出错：" + ex.Message);
            }
            FeatureClassTarget.Add(featcls);
            return true;
        }

        /// <summary>
        /// 创建简单要素类
        /// </summary>
        /// <param name="clsname"></param>
        /// <param name="geotype"></param>
        /// <param name="fds"></param>
        /// <param name="hasM_2"></param>
        /// <param name="hasZ_2"></param>
        /// <returns></returns>
        private IFeatureClass CreateSimple(string clsname, string geotype, IFields fds, bool hasM_2 = false, bool hasZ_2 = false)
        {
            IFieldsEdit fdsEdit = fds as IFieldsEdit;
            IField fd = new ESRI.ArcGIS.Geodatabase.Field();
            IFieldEdit fdEdit = fd as IFieldEdit;
            fdEdit.Name_2 = "OBJECTID";
            fdEdit.AliasName_2 = "OID";
            fdEdit.Type_2 = esriFieldType.esriFieldTypeOID;
            fdsEdit.AddField(fdEdit);

            IGeometryDef geoDef = new GeometryDef();
            IGeometryDefEdit pGeomDefEdit = geoDef as IGeometryDefEdit;
            pGeomDefEdit.GeometryType_2 = Convertor.GetGeometryType(geotype);
            pGeomDefEdit.SpatialReference_2 = SpatialRef;
            pGeomDefEdit.HasM_2 = hasM_2;
            pGeomDefEdit.HasZ_2 = hasZ_2;

            //创建Shape字段
            fd = new ESRI.ArcGIS.Geodatabase.Field();
            fdEdit = fd as IFieldEdit;
            fdEdit.Name_2 = "Shape";
            fdEdit.Type_2 = esriFieldType.esriFieldTypeGeometry;
            fdEdit.GeometryDef_2 = pGeomDefEdit;
            fdEdit.IsNullable_2 = true;
            fdEdit.Required_2 = true;
            fdsEdit.AddField(fdEdit);
            IObjectClassDescription objDes = new FeatureClassDescription() as IObjectClassDescription;
            if (DatasetTarget != null)
                return DatasetTarget.CreateFeatureClass(clsname, fds, objDes.InstanceCLSID, objDes.ClassExtensionCLSID, esriFeatureType.esriFTSimple, "SHAPE", "");
            else
                return (WorkspaceTarget as IFeatureWorkspace).CreateFeatureClass(clsname, fds, objDes.InstanceCLSID, objDes.ClassExtensionCLSID, esriFeatureType.esriFTSimple, "SHAPE", "");
        }
        
        /// <summary>
        /// 根据规则中的字段信息构建ArcGIS格式的字段
        /// </summary>
        /// <param name="attrFields">字段配置信息</param>
        /// <returns></returns>
        private IFields CreateFields(List<AttrField> attrFields)
        {
            IFields fds = new Fields();
            IFieldsEdit fdsEdit = fds as IFieldsEdit;
            List<string> names = new List<string>();
            foreach (AttrField fd in attrFields)
            {
                if (names.Contains(fd.TargetFieldName.ToLower().Trim())) continue;
                names.Add(fd.TargetFieldName.ToLower().Trim());
                IField f = CreateField(fd);
                fdsEdit.AddField(f);
            }
            IFieldChecker fdChecker = new FieldChecker();            
            fdChecker.ValidateWorkspace = WorkspaceTarget;
            IFields validatedFields = null;
            IEnumFieldError enumFieldError = null;
            fdChecker.Validate(fdsEdit, out enumFieldError, out validatedFields);
            if (enumFieldError != null)
            {
                IFieldError fieldError = null;
                while ((fieldError = enumFieldError.Next()) != null)
                {
                    IField errorField = fds.get_Field(fieldError.FieldIndex);
                    LogHelper.WriteErrLog("字段[" + errorField.Name + "]时出错：" + Convertor.GetInfo(fieldError.FieldError));
                }
                return null;
            }
            return fds;
        }

        /// <summary>
        /// 将自定义字段信息转成ArcGIS格式的字段
        /// </summary>
        /// <param name="field">自定义字段</param>
        /// <returns></returns>
        private IField CreateField(AttrField field)
        {
            IField fd = new ESRI.ArcGIS.Geodatabase.Field();
            IFieldEdit fdEdit = fd as IFieldEdit;
            fdEdit.IsNullable_2 = true;
            fdEdit.Editable_2 = true;
            fdEdit.Name_2 = field.TargetFieldName;
            fdEdit.AliasName_2 = field.Description;
            fdEdit.Type_2 = Convertor.GetFieldType(field.Type);
            int len = 0;
            int.TryParse(field.length, out len);
            int pre = 0;
            int.TryParse(field.precision, out len);
            int sca = 0;
            int.TryParse(field.scale, out sca);
            //根据字段类型判断该pField字段的属性信息
            switch (fdEdit.Type)
            {
                case esriFieldType.esriFieldTypeSmallInteger:
                case esriFieldType.esriFieldTypeInteger:
                    fdEdit.Precision_2 = pre == 0 ? 10 : pre; 
                    break;
                case esriFieldType.esriFieldTypeSingle:
                case esriFieldType.esriFieldTypeDouble:
                    fdEdit.Precision_2 = pre == 0 ? 38 : pre;
                    fdEdit.Scale_2 = sca == 0 ? 8 : sca; 
                    break;
                case esriFieldType.esriFieldTypeString:
                    fdEdit.Length_2 = len == 0 ? 255 : len; 
                    break;
            }
            return fd;
        }

        /// <summary>
        /// 将分类代码关联到所属图层中
        /// </summary>
        /// <param name="clsname">图层名称</param>
        /// <param name="rule">入库规则</param>
        /// <returns></returns>
        private List<FcodeRelation> CreateFcodeRelation(string clsname, DlgTargetFeatureClass rule)
        {           
            string[] geotype = new string[] { "点", "线", "面", "注记" };
            if (!geotype.Contains(rule.GeometryType))
            {
                string msg = string.Format("建库方案中图层[{0}:{1}]的几何类型[{2}]无效。目前几何类型仅支持：点、线、面、注记。",
                    rule.FeatureClassName, rule.FeatureClassAliasName, rule.GeometryType);
                LogHelper.WriteErrLog(msg);
                return null;
            }
            List<FcodeRelation> codes = new List<FcodeRelation>(); 
            if (rule.featureCodes == null || rule.featureCodes.Count == 0)
            {
                if (rule.GeometryType == "注记")
                {
                    codes.Add(new FcodeRelation()
                    {
                        GeometryType = rule.GeometryType,
                        DatasetName = clsname,
                        FCODE = "注记",
                        SOURCE = "注记",
                        FNAME = "注记"
                    });
                }
                return codes;
            }        
            foreach (FeatureCode itm in rule.featureCodes)
            {
                if (itm == null || string.IsNullOrWhiteSpace(itm.FCODE)) continue;
                codes.Add(new FcodeRelation()
                {
                    GeometryType = rule.GeometryType,
                    DatasetName = clsname,
                    FCODE = itm.FCODE.Trim(),
                    SOURCE = string.IsNullOrWhiteSpace(itm.SOURCE) ? itm.FCODE.Trim() : itm.SOURCE.Trim(),
                    FNAME = itm.FNAME
                });
            }
            return codes;
        }
        #endregion

        /// <summary>
        /// 进行代码入库
        /// </summary>
        /// <param name="soureFeatureClass">要入库的图层</param>
        /// <returns></returns>
        public bool IntoFCode(IFeatureClass soureFeatureClass)
        {
            if (soureFeatureClass == null) return true;
            string name = (soureFeatureClass as IDataset).Name;
            int cnt = soureFeatureClass.FeatureCount(null);
            if (cnt == 0)
            {
                LogHelper.WriteDoneLog(string.Format("要素类[{0}]中不存在要入库的数据。", name));
                return true;
            }            
            int idx = -1;
            if (!string.IsNullOrWhiteSpace(ImportRule.SourceFieldName))
            {
                string[] fnames = ImportRule.SourceFieldName.Split(',');
                foreach (string s in fnames)
                {
                    if (string.IsNullOrWhiteSpace(s)) continue;
                    idx = soureFeatureClass.FindField(s);
                    if (idx >= 0) break;
                }
            }            
            bool isAnno = (soureFeatureClass.FeatureType == esriFeatureType.esriFTAnnotation);//是否是注记层
            if (idx < 0 && !isAnno)
            {
                LogHelper.WriteErrLog(string.Format("要素类[{0}]中不存在入库字段[{1}]。", name, ImportRule.SourceFieldName));
                return false;
            }
            ProgressSub.SetMaxValue(cnt);
            IFeatureCursor srcCur = soureFeatureClass.Search(null, false);
            IFeature feat = null;
            IFeatureClass aimFeatCls = null;
            IFeatureCursor aimCursor = null;
            string aimName = "";
            int impcnt = 0;
            bool hasz = false;
            while ((feat = srcCur.NextFeature()) != null)
            {
                ProgressSub.Step();
                if (IsStop) break;
                object obj = idx < 0 ? null : feat.get_Value(idx);
                string code = obj == null ? "" : obj.ToString();
                if (string.IsNullOrWhiteSpace(code) && !isAnno)
                {
                    LogHelper.WriteErrLog(string.Format("要素类[{0}]中要素[{1}]的入库字段属性值为空，不能入库。", name, feat.OID));
                    continue;
                }
                FcodeRelation fc = FeatureCodes.FirstOrDefault(t =>
                    (!string.IsNullOrWhiteSpace(code) && (t.FCODE.Equals(code) || t.SOURCE.Contains(code))) ||
                    (isAnno && t.FCODE == "注记")
                    );
                if (fc == null)
                {
                    if (_NewFCodes == null) _NewFCodes = new List<string>();
                    if (_NewFCodes.Contains(code)) continue;
                    LogHelper.WriteErrLog(string.Format("分类代码[{0}]不在建库方案中，不能入库。", code));
                    _NewFCodes.Add(code);
                    continue;              
                }
                if (string.IsNullOrWhiteSpace(fc.DatasetName))
                {
                    LogHelper.WriteErrLog(string.Format("分类代码[{0}]所属的要素类为空，不能入库。", code));
                    continue;
                }
                if (!aimName.Equals(fc.DatasetName, StringComparison.CurrentCultureIgnoreCase))
                {
                    if (aimCursor != null)
                    {
                        aimCursor.Flush();
                        aimCursor = null;
                        aimFeatCls = null;                        
                    }
                    aimFeatCls = FeatureClassTarget.FirstOrDefault(t =>
                            ((t as IDataset).Name.Equals(fc.DatasetName, StringComparison.CurrentCultureIgnoreCase) ||
                            (t as IDataset).Name.ToLower().Contains(fc.DatasetName.ToLower())));
                    aimCursor = aimFeatCls.Insert(true);
                    aimName = fc.DatasetName;
                    hasz = aimFeatCls.HasZValue();
                }
                Dictionary<int, int> dcfds = GetFieldRels(soureFeatureClass, aimFeatCls);
                IFeatureBuffer featurebuffer = aimFeatCls.CreateFeatureBuffer();
                if (hasz) featurebuffer.Shape = GeometryHelper.Geom2Dto3D(feat.ShapeCopy);
                else featurebuffer.Shape = GeometryHelper.Geom3Dto2D(feat.ShapeCopy);
                //featurebuffer.Shape = feat.ShapeCopy;
                if (dcfds != null && dcfds.Count > 0)
                {
                    foreach (KeyValuePair<int, int> kvp in dcfds)
                    {
                        featurebuffer.set_Value(kvp.Key, feat.get_Value(kvp.Value));
                    }
                }
                aimCursor.InsertFeature(featurebuffer);
                impcnt++;
                if (impcnt % _FlushCount == 0)
                {
                    aimCursor.Flush();
                }
            }
            if (aimCursor != null)
            {
                aimCursor.Flush();
                aimCursor = null;
                aimFeatCls = null;
            }
            ProgressSub.Stop();
            LogHelper.WriteDoneLog(string.Format("要素类[{0}]已入库{1}/{2}。\n", name, impcnt, cnt));
            return (impcnt == cnt);
        }

        /// <summary>
        /// 进行代码入库
        /// </summary>
        /// <param name="soureFeatureClass">要入库的图层</param>
        /// <returns></returns>
        public bool IntoLayer(IFeatureClass soureFeatureClass)
        {
            if (soureFeatureClass == null) return true;
            bool hasz = false;
            string name = (soureFeatureClass as IDataset).Name;
            int cnt = soureFeatureClass.FeatureCount(null);
            if (cnt == 0)
            {
                LogHelper.WriteDoneLog(string.Format("要素类[{0}]中不存在要入库的数据。", name));
                return true;
            }
            MatchFieldName ms = MatchNames.FirstOrDefault(t => t.SourceName.Equals(name, StringComparison.CurrentCultureIgnoreCase));
            if (ms == null)
            {
                LogHelper.WriteErrLog(string.Format("要素类[{0}]没有匹配要入库的图层，不能进行入库。", name));
                return true;
            }
            string mname = ms.TargetName;
            IFeatureClass aimFeatCls = FeatureClassTarget.FirstOrDefault(t =>
                            ((t as IDataset).Name.Equals(mname, StringComparison.CurrentCultureIgnoreCase) ||
                            (t as IDataset).Name.ToLower().Contains(mname.ToLower())));
            if (aimFeatCls == null)
            {
                LogHelper.WriteErrLog(string.Format("没有找到匹配的要素类[{0}]，不能进行入库。", mname));
                return true;
            }
            Dictionary<int, int> dcfds = GetMatchFields(soureFeatureClass.Fields, aimFeatCls.Fields, ms.Fields, soureFeatureClass.FeatureType == esriFeatureType.esriFTAnnotation);            
            if (useAppendGP && soureFeatureClass.FeatureType!=esriFeatureType.esriFTAnnotation)   //快速入库（由于注记层APPEND会丢失属性，注记层跳过不使用快速入库方式）
                return ConvertByAppendGpTool(soureFeatureClass, aimFeatCls, ms.Fields);
            ProgressSub.SetMaxValue(cnt);
            hasz = aimFeatCls.HasZValue();
            IFeatureCursor srcCur = soureFeatureClass.Search(null, false);
            IFeature feat = null;
            IFeatureCursor aimCursor = aimFeatCls.Insert(true);
            int impcnt = 0;
            while ((feat = srcCur.NextFeature()) != null)
            {
                ProgressSub.Step();
                if (IsStop) break;
                IFeatureBuffer featurebuffer = aimFeatCls.CreateFeatureBuffer();
                if (hasz) featurebuffer.Shape = GeometryHelper.Geom2Dto3D(feat.ShapeCopy);
                else featurebuffer.Shape = GeometryHelper.Geom3Dto2D(feat.ShapeCopy);
                if (dcfds != null && dcfds.Count > 0)
                {
                    foreach (KeyValuePair<int, int> kvp in dcfds)
                    {
                        featurebuffer.set_Value(kvp.Key, feat.get_Value(kvp.Value));
                    }
                }
                aimCursor.InsertFeature(featurebuffer);
                impcnt++;
                if (impcnt % _FlushCount == 0) aimCursor.Flush();
            }
            if (aimCursor != null)
            {
                aimCursor.Flush();
                aimCursor = null;
                aimFeatCls = null;
            }
            ProgressSub.Stop();
            string msg = string.Format("要素类[{0}]已入库{1}/{2}。", name, impcnt, cnt);
            if (impcnt == cnt) LogHelper.WriteDoneLog(msg);
            else LogHelper.WriteErrLog(msg);
            return (impcnt == cnt);
        }

        /// <summary>
        /// 获取字段对应关系
        /// </summary>
        /// <param name="source">源字段</param>
        /// <param name="target">目标字段</param>
        /// <returns></returns>
        private Dictionary<int, int> GetFieldRels(IFeatureClass source, IFeatureClass target)
        {
            if (MatchIndexes == null) MatchIndexes = new List<MatchFieldIndex>();
            string srcname = (source as IDataset).Name;
            string aimname = (target as IDataset).Name;
            MatchFieldIndex fr = MatchIndexes.FirstOrDefault(t => (t.SourceName.Equals(srcname, StringComparison.CurrentCultureIgnoreCase) &&
                 t.TargetName.Equals(aimname, StringComparison.CurrentCultureIgnoreCase)));
            if (fr != null) return fr.Fields;
            Dictionary<int, int> dcfds = GetMatchFields(source.Fields, target.Fields);
            MatchIndexes.Add(new MatchFieldIndex()
            {
                SourceName = srcname,
                TargetName = aimname,
                Fields = dcfds
            });
            return dcfds;
        }

        /// <summary>
        /// 获取字段匹配关系
        /// </summary>
        /// <param name="srcFields">源字段</param>
        /// <param name="aimFields">目标字段</param>
        /// <param name="matchFields">已匹配的关系</param>
        /// <param name="isanno">是否为注记层，注记需要匹配系统字段</param>
        /// <returns></returns>
        private Dictionary<int, int> GetMatchFields(IFields srcFields, IFields aimFields, Dictionary<string, string> matchFields = null, bool isanno = false)
        {
            Dictionary<int, int> dcfds = new Dictionary<int, int>();
            for (int i = 0; i < aimFields.FieldCount; i++)
            {
                IField f = aimFields.get_Field(i);
                if (f.Type == esriFieldType.esriFieldTypeOID || f.Type == esriFieldType.esriFieldTypeGeometry) continue;
                if (!f.Editable) continue;
                string srcname2 = f.Name;
                if (matchFields != null && matchFields.Count > 0)
                {
                    KeyValuePair<string, string> kvp = matchFields.FirstOrDefault(t => t.Value.Equals(srcname2, StringComparison.CurrentCultureIgnoreCase));
                    if (string.IsNullOrWhiteSpace(kvp.Key))
                    {
                        if (!isanno) continue;
                    }
                    else srcname2 = kvp.Key;
                }
                int idx = srcFields.FindField(srcname2);
                if (idx < 0) continue;
                dcfds.Add(i, idx);
            }
            return dcfds;
        }

        private bool ImportByCopyGpTool(IFeatureClass SourceFeatCls)
        {
            try
            {
                bool success;
                IDataset pDataset = SourceFeatCls as IDataset;
                DateTime dt = DateTime.Now;
                //string newFclsName=pDataset.Name+"_"+dt.Year+dt.Month.ToString().PadLeft(2, '0') + dt.Day.ToString().PadLeft(2, '0');
                string newFclsName = pDataset.Name;
                if (string.IsNullOrEmpty(Affix) == false) newFclsName += "_" + Affix;
               string sourcePath;
                if (SourceFeatCls.FeatureDataset != null)
                {
                    sourcePath = PlanningGIS.ArcGIS.WorkspaceHelper.GetConnectionAffix(pDataset.Workspace) + "\\" + SourceFeatCls.FeatureDataset.Name + "\\" + pDataset.Name;
                }
                else
                {
                    sourcePath = PlanningGIS.ArcGIS.WorkspaceHelper.GetConnectionAffix(pDataset.Workspace) + "\\" + pDataset.Name;
                }

             //   pDataset = TargetFeatCls as IDataset;
              
                LogHelper.WriteLog("正在将数据源[" + sourcePath + "]中的要素入到目标要素类[" + newFclsName + "]中...");

                ESRI.ArcGIS.DataManagementTools.CopyFeatures copy = new CopyFeatures();
                copy.in_features = SourceFeatCls;
                copy.out_feature_class =string.IsNullOrEmpty(FeatureDatasetName)?  SdeFile+"\\"+newFclsName: SdeFile + "\\"+FeatureDatasetName +"\\"+ newFclsName;
               
            

         

                string strMsg;
                success = GeoprocessorHelper.Execute(copy, out strMsg);

                if (success)
                {
                    LogHelper.WriteDoneLog(strMsg);
                }
                else
                {
                    LogHelper.WriteErrLog(strMsg);
                }
                return success;
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrLog("转换失败：" + ex.Message + "\n");
                return false;
            }
     
           
        }
        /// <summary>
        /// 通过Append GP工具进行数据转换，不能设置过滤条件和代码对应关系
        /// </summary>
        /// <returns></returns>
        private bool ConvertByAppendGpTool(IFeatureClass SourceFeatCls, IFeatureClass TargetFeatCls, Dictionary<string, string> MatchFields)
        {
            try
            {
                bool success;
                IDataset pDataset = SourceFeatCls as IDataset;
                string sourcePath;
                if (SourceFeatCls.FeatureDataset != null)
                {
                    sourcePath = PlanningGIS.ArcGIS.WorkspaceHelper.GetConnectionAffix(pDataset.Workspace) + "\\" + SourceFeatCls.FeatureDataset.Name + "\\" + pDataset.Name;
                }
                else
                {
                    sourcePath = PlanningGIS.ArcGIS.WorkspaceHelper.GetConnectionAffix(pDataset.Workspace) + "\\" + pDataset.Name;
                }

                pDataset = TargetFeatCls as IDataset;
                //string targetPath;
                //if (TargetFeatCls.FeatureDataset != null)
                //{
                //    IFeatureLayer pFeatLyr = new FeatureLayerClass();
                //    pFeatLyr.FeatureClass = TargetFeatCls;
                //    IDataset pDs = pFeatLyr as IDataset;

                //    targetPath = PlanningGIS.ArcGIS.WorkspaceHelper.GetConnectionAffix(pDataset.Workspace) + "\\" + TargetFeatCls.FeatureDataset.Name + "\\" + pDataset.Name;
                //}
                //else
                //{
                //    targetPath = PlanningGIS.ArcGIS.WorkspaceHelper.GetConnectionAffix(pDataset.Workspace) + "\\" + pDataset.Name;
                //}

                LogHelper.WriteLog("正在将数据源[" + sourcePath + "]中的要素入到目标要素类[" + TargetFeatCls.AliasName + "]中...");

                Append append = new Append();
                append.inputs = sourcePath;
                append.target = pDataset;
                //append.target = targetPath;
                append.schema_type = "NO_TEST";

                #region 设置字段对应关系
                if (MatchFields != null && MatchFields.Count > 0)
                {
                    string fieldMap = "";
                    foreach (KeyValuePair<string, string> kvp in MatchFields)
                    {
                        string targetFieldName = kvp.Key;
                        string sourceFieldName = kvp.Value;

                        if (sourceFieldName == "") continue;

                        string targetFieldAliasName = TargetFeatCls.Fields.get_Field(TargetFeatCls.FindField(targetFieldName)).AliasName;

                        IField pField = SourceFeatCls.Fields.get_Field(SourceFeatCls.FindField(sourceFieldName));
                        switch (pField.Type)
                        {
                            case esriFieldType.esriFieldTypeGlobalID:
                                fieldMap = fieldMap + targetFieldName + " '" + targetFieldAliasName + "' false false true 38 Text 0 0,First,#," + sourcePath + "," + sourceFieldName + ",-1,-1;";
                                break;
                            case esriFieldType.esriFieldTypeSmallInteger:
                                fieldMap = fieldMap + targetFieldName + " '" + targetFieldAliasName + "' " + pField.IsNullable.ToString().ToLower() + " true false 2 Short 0 5,First,#," + sourcePath + "," + sourceFieldName + ",-1,-1;";
                                break;

                            case esriFieldType.esriFieldTypeInteger:
                                fieldMap = fieldMap + targetFieldName + " '" + targetFieldAliasName + "' " + pField.IsNullable.ToString().ToLower() + " true false 4 Long 0 0,First,#," + sourcePath + "," + sourceFieldName + ",-1,-1;";
                                break;

                            case esriFieldType.esriFieldTypeString:
                                fieldMap = fieldMap + targetFieldName + " '" + targetFieldAliasName + "' " + pField.IsNullable.ToString().ToLower() + " true false 255 Text 0 0,First,#," + sourcePath + "," + sourceFieldName + ",-1,-1;";
                                break;

                            case esriFieldType.esriFieldTypeDouble:
                                fieldMap = fieldMap + targetFieldName + " '" + targetFieldAliasName + "' " + pField.IsNullable.ToString().ToLower() + " true false 0 Double 0 0,First,#," + sourcePath + "," + sourceFieldName + ",-1,-1;";
                                break;

                            case esriFieldType.esriFieldTypeBlob:
                                fieldMap = fieldMap + targetFieldName + " '" + targetFieldAliasName + "' " + pField.IsNullable.ToString().ToLower() + " true false 0 Blob 0 0,First,#," + sourcePath + "," + sourceFieldName + ",-1,-1;";
                                break;

                            default:   //有待完善更多的字段类型
                                fieldMap = fieldMap + targetFieldName + " '" + targetFieldAliasName + "', First,#," + sourcePath + ", " + sourceFieldName + ",-1,-1;";
                                break;
                        }
                    }
                    if (fieldMap != "")
                    {
                        fieldMap = fieldMap.Substring(0, fieldMap.Length - 1);
                        append.field_mapping = fieldMap;
                    }
                }
                #endregion

                string strMsg;
                success = GeoprocessorHelper.Execute(append, out strMsg);

                if (success)
                {
                    LogHelper.WriteDoneLog(strMsg);
                }
                else
                {
                    LogHelper.WriteErrLog(strMsg);
                }
                return success;
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrLog("转换失败：" + ex.Message + "\n");
                return false;
            }
        }
        
    }

    /// <summary>
    /// 要导入的图层与目标图层的字段匹配关系
    /// </summary>
    public abstract class MatchField
    {
        /// <summary>
        /// 要入库的源要素类名称
        /// </summary>
        public string SourceName { get; set; }

        /// <summary>
        /// 要入到的目标要素类
        /// </summary>
        public string TargetName { get; set; }
    }

    /// <summary>
    /// 字段名称匹配关系
    /// </summary>
    public class MatchFieldName : MatchField
    {
        /// <summary>
        /// 目标要素类与源要素类字段的对应关系
        /// </summary>
        public Dictionary<string, string> Fields { get; set; }
    }

    /// <summary>
    /// 字段索引匹配关系
    /// </summary>
    public class MatchFieldIndex : MatchField
    {
        /// <summary>
        /// 目标要素类与源要素类字段的对应关系
        /// </summary>
        public Dictionary<int, int> Fields { get; set; }
    }
    
}
